﻿using System;
using System.Collections.Generic;

namespace Framework.FSM
{
    /// <summary>
    /// 状态机类
    /// </summary>
    public class FSM : IFSM
    {
        private Dictionary<string, IFsmState> m_States = new Dictionary<string, IFsmState>();
        private IFsmState m_CurrentState = null;
        private float m_CurrentStateTime = 0;
        private bool m_IsRunning = false;
        private string m_Name = string.Empty;
        private object m_Owner = null;

        public IFsmState CurrentState
        {
            get
            {
                return m_CurrentState;
            }
            private set
            {
                m_CurrentState = value;
            }
        }
        public float CurrentStateTime
        {
            get
            {
                return m_CurrentStateTime;
            }
            private set
            {
                m_CurrentStateTime = value;
            }
        }
        public bool IsRunning
        {
            get
            {
                return m_IsRunning;
            }
            private set
            {
                m_IsRunning = value;
            }
        }
        public string Name
        {
            get
            {
                return m_Name;
            }
            private set
            {
                m_Name = value;
            }
        }
        public object Owner
        {
            get
            {
                return m_Owner;
            }
            private set
            {
                m_Owner = value;
            }
        }

        public void AddState<T>() where T : IFsmState, new()
        {
            string typeName = typeof(T).ToString();
            if (m_States.ContainsKey(typeName))
                return;
            T t = new T();
            t.Init(this);
            m_States.Add(typeName, t);
        }
        public void AddState(IFsmState state)
        {
            if (state == null) return;
            string typeName = state.GetType().ToString();
            if (m_States.ContainsKey(typeName))
                return;
            state.Init(this);
            m_States.Add(typeName, state);
        }
        public void RemoveState<T>() where T : IFsmState
        {
            string typeName = typeof(T).ToString();
            IFsmState state = null;
            if(m_States.TryGetValue(typeName, out state))
            {
                state.Destroy(this);
                m_States.Remove(typeName);
            }
        }
        public T GetState<T>() where T : class, IFsmState
        {
            string typeName = typeof(T).ToString();
            if (m_States.ContainsKey(typeName))
                return m_States[typeName] as T;
            return null;
        }
        public void ChangeState<T>(FsmStateDataBase data)
        {
            string typeName = typeof(T).ToString();
            IFsmState state = null;
            if(m_States.TryGetValue(typeName, out state))
            {
                if (CurrentState != null)
                    CurrentState.Exit(this);
                state.Enter(this, data);
                CurrentState = state;
            }
        }
        public void ChangeState(IFsmState state, FsmStateDataBase data)
        {
            if (state == null) return;
            if (CurrentState != null)
                CurrentState.Exit(this);
            state.Enter(this, data);
            CurrentState = state;
        }
        public void DestroyFsm()
        {
            if(CurrentState != null)
                CurrentState.Exit(this);
            CurrentState = null;
            foreach (var item in m_States)
            {
                item.Value.Destroy(this);
            }
            m_States.Clear();
            IsRunning = false;
            Name = null;
            Owner = null;
            CurrentStateTime = 0;
        }
        public void InitFsm(object owner, string fsmName, List<IFsmState> states)
        {
            CurrentStateTime = 0;
            CurrentState = null;
            Name = fsmName;
            Owner = owner;
            if(states != null)
            {
                for (int i = 0; i < states.Count; i++)
                {
                    AddState(states[i]);
                }
            }
            IsRunning = true;
        }
        public void PauseFsm()
        {
            if (CurrentState != null)
                CurrentState.Pause(this);
            IsRunning = false;
        }
        public void ResetFsm()
        {
            if (CurrentState != null)
                CurrentState.Reset(this);
            IsRunning = true;
            CurrentStateTime = 0;
            CurrentState = null;
        }
        public void ResumeFsm()
        {
            if (CurrentState != null)
                CurrentState.Resume(this);
            IsRunning = true;
        }
        public void Update(float frameTime, float realTime)
        {
            if (!IsRunning) return;
            if (CurrentState != null)
                CurrentState.Update(frameTime, realTime);
            CurrentStateTime += realTime;
        }
        public void GetAllStateType(ref List<IFsmState> list)
        {
            if (list == null) return;
            foreach (var item in m_States)
            {
                list.Add(item.Value);
            }
        }
    }
}
